using System;
using System.Collections;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;

public class SceneLoader : MonoBehaviour, ISaveAble {

    public Transform playerTrans;               // 玩家的位置
    public Vector3 firstPosition;               // 玩家进入第一个场景的位置（新的冒险）
    public Vector3 menuPostion;                 // 玩家在主菜单显示的位置

    [Header("事件监听")]
    public SceneLoadEventSO loadSceneEventSO;   // 场景加载事件的SO
    public SceneLoadEventSO unloadSceneEvent;   // 场景卸载事件的SO
    public VoidEventSO newGameEvent;            // 新游戏事件的SO
    public VoidEventSO backToMenuEvent;         // 退回到主菜单

    [Header("广播")]
    public VoidEventSO afterSceneLoadedEvent;   // 场景加载完毕后执行的事件广播
    public FadeEventSO fadeEvent;               // 淡入淡出的事件广播

    [Header("场景")]
    public GameSceneSO firstLoadScene;          // 点击新的冒险进入的场景
    public GameSceneSO menuScene;               // 主菜单场景
    [SerializeField] private GameSceneSO currentLoadedScene;     // 当前加载的场景
    private GameSceneSO sceneToLoad;            // 将要跳转的场景
    private Vector3 positionToGo;               // 跳转场景后角色的初始位置
    private bool fadeScreen;                    // 是否需要淡入淡出
    private bool isLoading;                     // 是否正在加载场景

    [Header("淡入淡出的等待时间")]
    public float fadeDuration;                  // 淡入淡出的等候时间

    private void Awake() {
        // Addressables.LoadSceneAsync(firstLoadScene.sceneReference, LoadSceneMode.Additive);

        // currentLoadedScene = firstLoadScene;
        /*
            这里为什么不用注释掉的那行的实现方法，因为上边那种写法，
            加载了firstLoadScene之后，只是将其SO赋值给了currentLoadedScene，
            而没有真正对currentLoadedScene进行加载，没有进行加载后边自然也就不能对currentLoadedScene进行卸载
        */
        // currentLoadedScene.sceneReference.LoadSceneAsync(LoadSceneMode.Additive);
    }

    private void Start() {
        // NewGame();
        loadSceneEventSO.RaiseLoadRequestEvent(menuScene, menuPostion, true);   // 游戏第一次启动的时候加载Menu场景
    }

    private void OnEnable() {
        loadSceneEventSO.LoadRequestEvent += OnLoadRequestEvent;
        newGameEvent.OnEventRaised += NewGame;
        backToMenuEvent.OnEventRaised += OnBackToMenuEvent;

        ISaveAble saveAble = this;
        saveAble.RegisterSaveData();
    }

    private void OnDisable() {
        loadSceneEventSO.LoadRequestEvent -= OnLoadRequestEvent;
        newGameEvent.OnEventRaised -= NewGame;
        backToMenuEvent.OnEventRaised -= OnBackToMenuEvent;

        ISaveAble saveAble = this;
        saveAble.UnRegisterSaveData();
    }

    private void OnBackToMenuEvent() {
        sceneToLoad = menuScene;
        loadSceneEventSO.RaiseLoadRequestEvent(sceneToLoad, menuPostion, true);
    }

    private void NewGame() {
        sceneToLoad = firstLoadScene;
        loadSceneEventSO.RaiseLoadRequestEvent(sceneToLoad, firstPosition, true);
    }

    /// <summary>
    /// 场景加载事件请求
    /// </summary>
    /// <param name="locationToLoad"></param>
    /// <param name="posToGo"></param>
    /// <param name="fadeScreen"></param>
    private void OnLoadRequestEvent(GameSceneSO locationToLoad, Vector3 posToGo, bool fadeScreen) {
        if (isLoading) {    // 如果当前已经处于加载场景的状态下，则不需要进行下边的逻辑了。
            return;
        }

        isLoading = true;
        sceneToLoad = locationToLoad;
        positionToGo = posToGo;
        this.fadeScreen = fadeScreen;

        if (currentLoadedScene != null) {
            StartCoroutine(UnLoadPrevioisScene());
        } else {
            LoadNewScene();
        }
    }

    private IEnumerator UnLoadPrevioisScene() {
        if (fadeScreen) {   // 逐渐变黑
            fadeEvent.FadeIn(fadeDuration);
        }

        yield return new WaitForSeconds(fadeDuration);      // 在淡入淡出的效果执行完毕前暂时停止程序的运行

        // 广播事件调整血条显示
        unloadSceneEvent.RaiseLoadRequestEvent(sceneToLoad, positionToGo, true);

        yield return currentLoadedScene.sceneReference.UnLoadScene();   // 卸载当前场景

        playerTrans.gameObject.SetActive(false);    // 关闭人物

        LoadNewScene();     // 加载要跳转的场景
    }

    private void LoadNewScene() {
        Debug.Log("加载新场景");

        var loadingOption = sceneToLoad.sceneReference.LoadSceneAsync(LoadSceneMode.Additive, true);    // 加载场景
        loadingOption.Completed += OnLoadCompleted;     // 场景加载完毕后执行
    }

    private void OnLoadCompleted(AsyncOperationHandle<SceneInstance> handle) {
        currentLoadedScene = sceneToLoad;           // 将加载的场景赋值给当前场景

        playerTrans.position = positionToGo;        // 玩家的新场景位置

        playerTrans.gameObject.SetActive(true);     // 将人物对象激活

        if (fadeScreen) {   // 逐渐变透明
            fadeEvent.FadeOut(fadeDuration);
        }

        isLoading = false;  // 加载完毕，将isLoading状态复位
        
        if (currentLoadedScene.sceneType == SceneType.Location) {   // 只有当前加载场景是游戏关卡时，才需要进行后边的操作
            afterSceneLoadedEvent.RaiseEvent();     // 场景加载完成后的事件，获取摄像机bounds范围、激活人物控制等
        }
    }

    public DataDefination GetDataID() {
        return GetComponent<DataDefination>();
    }

    public void GetSaveData(Data data) {
        data.SaveGameScene(currentLoadedScene);
    }

    public void LoadData(Data data) {
        var playerID = playerTrans.GetComponent<DataDefination>().ID;
        if (data.characterPosDict.ContainsKey(playerID)) {
            positionToGo = data.characterPosDict[playerID].ToVector3();   // 上一次存档点中，角色的位置
            sceneToLoad = data.GetSavedScene();     // 上一次存档点的场景

            OnLoadRequestEvent(sceneToLoad, positionToGo, true);
        }
    }
}